#include "modbus_slave.h"
#include "user_lib.h"
#include "user_msg.h"

// 超时标志，3.5字符超时置1
static uint8_t g_mods_timeout = 0;

// 用来存放功能码数据的应答,可封装进行数据管理
uint8_t REG_DXX_Status[10];
uint8_t REG_TXX_Status[10];
uint16_t REG_P01_Value;
uint16_t REG_P02_Value;
uint16_t REG_A01_Value;

// 声明一个结构体
MODS_T g_tMods;

static void MODS_AnalyzeApp(void);

/* 为RTU数据加上CRC校验 */
static void MODS_SendWithCRC(uint8_t *pBuf, uint8_t ucLen)
{
	uint16_t crc;
	uint8_t buf[S_TX_BUF_SIZE];

	memcpy(buf, pBuf, ucLen);
	crc = CRC16_Modbus(pBuf, ucLen);
	buf[ucLen++] = crc >> 8;		// 低字节在前
	buf[ucLen++] = crc;

	RS485_SendBuf(buf, ucLen);
}

/* 发送错误应答 */
static void MODS_SendAckErr(uint8_t errCode)
{
	uint8_t txBuf[3];

	txBuf[0] = g_tMods.RxBuf[0];						// 地址
	txBuf[1] = g_tMods.RxBuf[1] | 0x80;			// 异常功能码
	txBuf[2] = errCode;

	MODS_SendWithCRC(txBuf, 3);
}

/* 发送正确的应答 */
static void MODS_SendAckOk(void)
{
	uint8_t txBuf[6];
	uint8_t i;

	for(i=0; i<6; i++)
	{
		txBuf[i] = g_tMods.RxBuf[i];
	}

	MODS_SendWithCRC(txBuf, 6);
}

/* 功能码01：数据解析并应答 */
static void MODS_01H(void)
{
/* 
例:
	发: 01 01 00 01 00 01 AC 0A
	收: 01 01 01 00 51 88 
*/
	uint16_t reg;
	uint16_t num;
	uint16_t i;
	uint16_t m;
	uint8_t status[10];
	
	g_tMods.RspCode = RSP_OK;
	// 主机发送的01功能码的数据长度必须为8个字节
	if(g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;
		return ;
	}

	reg = BEBufToUint16(&g_tMods.RxBuf[2]);		// 寄存器地址
	num = BEBufToUint16(&g_tMods.RxBuf[4]);		// 寄存器数量

	m = (num + 7) / 8;		// 返回字节个数
	// 寄存器地址合法性判断
	if((reg >= REG_D01) && (num > 0) && (reg + num <= REG_DXX + 1))
	{
		for(i=0; i<m; i++)
		{
			status[i] = 0;		// 先清空
		}
		// 应答数据
		for(i=0; i<num; i++)
		{
			status[i / 8] = REG_DXX_Status[i / 8];
		}
	}
	else
	{
		g_tMods.RspCode = RSP_ERR_REG_ADDR;			// 寄存器地址错误
	}

	if(g_tMods.RspCode == RSP_OK)
	{
		g_tMods.TxCount = 0;
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[0];		// 地址
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[1];		// 功能码
		g_tMods.TxBuf[g_tMods.TxCount++] = m;										// 返回字节数

		for(i=0; i<m; i++)
		{
			g_tMods.TxBuf[g_tMods.TxCount++] = status[i];					// 数据内容		
		}

		MODS_SendWithCRC(g_tMods.TxBuf, g_tMods.TxCount);
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		// 发送错误码
	}
}

/* 功能码02：数据解析并应答 */
static void MODS_02H(void)
{
/*
例:
	发：01 02 00 21 00 04 29 C3
	收: 01 02 01 00 A1 88 
*/
	uint16_t reg;
	uint16_t num;
	uint16_t i;
	uint16_t m;
	uint8_t status[10];
	
	g_tMods.RspCode = RSP_OK;
	if(g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;
		return ;
	}	

	reg = BEBufToUint16(&g_tMods.RxBuf[2]);		// 寄存器地址
	num = BEBufToUint16(&g_tMods.RxBuf[4]);		// 寄存器数量

	m = (num + 7) / 8;		// 返回字节个数	

	// 寄存器地址合法性判断
	if((reg >= REG_T01) && (num > 0) && (reg + num <= REG_TXX + 1))
	{
		for(i=0; i<m; i++)
		{
			status[i] = 0;		// 先清空
		}
		// 应答数据
		for(i=0; i<num; i++)
		{
			status[i / 8] = REG_TXX_Status[i / 8];
		}
	}
	else
	{
		g_tMods.RspCode = RSP_ERR_REG_ADDR;			// 寄存器地址错误
	}	

	if(g_tMods.RspCode == RSP_OK)
	{
		g_tMods.TxCount = 0;
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[0];		// 地址
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[1];		// 功能码
		g_tMods.TxBuf[g_tMods.TxCount++] = m;										// 返回字节数

		for(i=0; i<m; i++)
		{
			g_tMods.TxBuf[g_tMods.TxCount++] = status[i];					// 数据内容		
		}

		MODS_SendWithCRC(g_tMods.TxBuf, g_tMods.TxCount);
	}	
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		// 发送错误码
	}	
}

/**
 * @brief 	读保持寄存器的值
 * @param		reg_addr: 寄存器地址	
 * @param		reg_value: 读到的寄存器的值
 * @retval	1表示OK 0表示错误	
 * @note
 */
static uint8_t MODS_ReadRegValue(uint16_t reg_addr, uint8_t *reg_value)
{
	uint16_t value;

	switch(reg_addr)
	{
	case SLAVE_REG_P01:
		value = REG_P01_Value;
		break;

	case SLAVE_REG_P02:
		value = REG_P02_Value;
		break;
	
	default:
		return 0;
	}

	reg_value[0] = value >> 8;
	reg_value[1] = value;

	return 1;
}

/**
 * @brief 	写保持寄存器的值
 * @param		reg_addr: 寄存器地址	
 * @param		reg_value: 写入的寄存器的值
 * @retval	1表示OK 0表示错误	
 * @note
 */
static uint8_t MODS_WriteRegValue(uint16_t reg_addr, uint16_t reg_value)
{
	switch(reg_addr)
	{
	case SLAVE_REG_P01:
		REG_P01_Value = reg_value;
		break;

	case SLAVE_REG_P02:
		REG_P02_Value = reg_value;
		break;
	
	default:
		return 0;	
	}

	return 1;
}

/* 功能码03：数据解析并应答 */
static void MODS_03H(void)
{
	uint16_t reg;
	uint16_t num;
	uint16_t i;
	uint8_t reg_value[64];

	g_tMods.RspCode = RSP_OK;

	if(g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;
		goto err_ret;
	}

	reg = BEBufToUint16(&g_tMods.RxBuf[2]); 				/* 寄存器号 */
	num = BEBufToUint16(&g_tMods.RxBuf[4]); 				/* 寄存器个数 */
	// 提前准备的应答数据区大小不够
	if(num > sizeof(reg_value) / 2)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;
		goto err_ret;		
	}

	for(i=0; i<num; i++)
	{
		// 读出寄存器中的值
		if(MODS_ReadRegValue(reg, &reg_value[2 * i]) == 0)
		{
			g_tMods.RspCode = RSP_ERR_REG_ADDR;				/* 寄存器地址错误 */
			break;
		}
		reg++;
	}

err_ret:
	if(g_tMods.RspCode == RSP_OK)
	{
		g_tMods.TxCount = 0;
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[0];		// 地址
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[1];		// 功能码
		g_tMods.TxBuf[g_tMods.TxCount++] = num * 2;			

		for(i=0; i<num; i++)
		{
			g_tMods.TxBuf[g_tMods.TxCount++] = reg_value[2 * i];
			g_tMods.TxBuf[g_tMods.TxCount++] = reg_value[2 * i + 1];			
		}	
		MODS_SendWithCRC(g_tMods.TxBuf, g_tMods.TxCount);
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		// 发送错误码
	}
}


/* 功能码04：数据解析并应答 */
static void MODS_04H(void)
{
	uint16_t reg;
	uint16_t num;
	uint16_t i;
	uint16_t status[10];

	memset(status, 0, 10);

	g_tMods.RspCode = RSP_OK;
	
	if(g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;
		goto err_ret;
	}
	
	reg = BEBufToUint16(&g_tMods.RxBuf[2]); 	/* 寄存器号 */
	num = BEBufToUint16(&g_tMods.RxBuf[4]); /* 寄存器个数 */

	if((reg >= REG_A01) && (num > 0) && (reg + num <= REG_AXX + 1))
	{
		for (i = 0; i < num; i++)
		{
			switch(reg)
			{
			case REG_A01:
				status[i] = REG_A01_Value;
				break;
			
			default:
				status[i] = 0;
				break;
			}

			reg++;
		}
	}
	else
	{
		g_tMods.RspCode = RSP_ERR_REG_ADDR;			// 寄存器地址错误	
	}

err_ret:
	if (g_tMods.RspCode == RSP_OK)		/* 正确应答 */
	{
		g_tMods.TxCount = 0;
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[0];
		g_tMods.TxBuf[g_tMods.TxCount++] = g_tMods.RxBuf[1];
		g_tMods.TxBuf[g_tMods.TxCount++] = num * 2; 		/* 返回字节数 */

		for (i = 0; i < num; i++)
		{
			g_tMods.TxBuf[g_tMods.TxCount++] = status[i] >> 8;
			g_tMods.TxBuf[g_tMods.TxCount++] = status[i] & 0xFF;
		}
		MODS_SendWithCRC(g_tMods.TxBuf, g_tMods.TxCount);
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode); /* 告诉主机命令错误 */
	}
}

/* 功能码05：数据解析并应答 */
static void MODS_05H(void)
{
/*
例：
	发：01 05 00 01 FF 00 DD FA
	收: 01 05 00 01 FF 00 DD FA

	发：	01 05 00 01 00 00 9C 0A
	收: 01 05 00 01 00 00 9C 0A
*/

	uint16_t reg;
	uint16_t value;

	g_tMods.RspCode = RSP_OK;
	
	if (g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;		/* 数据值域错误 */
		goto err_ret;
	}
	
	reg = BEBufToUint16(&g_tMods.RxBuf[2]); 	/* 寄存器号 */
	value = BEBufToUint16(&g_tMods.RxBuf[4]);	/* 数据 */

	if((value != 0) && (value != 0xFF00))
	{
		g_tMods.RspCode = RSP_ERR_VALUE;		/* 数据值域错误 */
		goto err_ret;		
	}
	// 下面可用数据封装进行处理
	if(reg == REG_D01)
	{
		value == 0? (REG_DXX_Status[0] &= ~0x01) : (REG_DXX_Status[0] |= 0x01);
	}
	else if(reg == REG_D02)
	{
		value == 0? (REG_DXX_Status[0] &= ~0x02) : (REG_DXX_Status[0] |= 0x02);
	}
	else if(reg == REG_D03)
	{
		value == 0? (REG_DXX_Status[0] &= ~0x04) : (REG_DXX_Status[0] |= 0x04);
	}

err_ret:
	if (g_tMods.RspCode == RSP_OK)				/* 正确应答 */
	{
		MODS_SendAckOk();
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		/* 告诉主机命令错误 */
	}	
}

/* 功能码06：数据解析并应答 */
static void MODS_06H(void)
{
	uint16_t reg;
	uint16_t value;

	g_tMods.RspCode = RSP_OK;

	if (g_tMods.RxCount != 8)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;		/* 数据值域错误 */
		goto err_ret;
	}	

	reg = BEBufToUint16(&g_tMods.RxBuf[2]); 	/* 寄存器号 */
	value = BEBufToUint16(&g_tMods.RxBuf[4]); /* 数据 */

	if(MODS_WriteRegValue(reg, value) == 1)
	{
		;
	}
	else
	{
		g_tMods.RspCode = RSP_ERR_REG_ADDR;			// 寄存器地址错误
	}
	
err_ret:
	if (g_tMods.RspCode == RSP_OK)				/* 正确应答 */
	{
		MODS_SendAckOk();
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		/* 告诉主机命令错误 */
	}	
}


/* 功能码10：数据解析并应答 */
static void MODS_10H(void)
{
	uint16_t reg_addr;
	uint16_t reg_num;
	uint8_t byte_num;
	uint8_t i;
	uint16_t value;
	
	g_tMods.RspCode = RSP_OK;	
	if (g_tMods.RxCount < 11)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;		/* 数据值域错误 */
		goto err_ret;
	}		

	reg_addr = BEBufToUint16(&g_tMods.RxBuf[2]);	/* 寄存器号 */
	reg_num = BEBufToUint16(&g_tMods.RxBuf[4]); 	/* 寄存器个数 */
	byte_num = g_tMods.RxBuf[6];									/* 后面的数据体字节数 */

	if(byte_num != reg_num * 2)
	{
		g_tMods.RspCode = RSP_ERR_VALUE;		/* 数据值域错误 */
		goto err_ret;		
	}

	for(i=0; i<reg_num; i++)
	{
		value = BEBufToUint16(&g_tMods.RxBuf[7 + 2 * i]);		/* 寄存器值 */
		if(MODS_WriteRegValue(reg_addr + i, value) == 1)
		{
			;
		}
		else
		{
			g_tMods.RspCode = RSP_ERR_REG_ADDR;			// 寄存器地址错误
			break;	
		}
	}

err_ret:
	if (g_tMods.RspCode == RSP_OK)				/* 正确应答 */
	{
		MODS_SendAckOk();
	}
	else
	{
		MODS_SendAckErr(g_tMods.RspCode);		/* 告诉主机命令错误 */
	}		
}


/* 解析回复处理，需要轮询调用 */
void MODS_Poll(void)
{
	uint16_t addr;
	uint16_t crc1;

	if(g_mods_timeout == 0)
	{
		return ;		// 没有超时继续接收
	}

	g_mods_timeout = 0;
	// 接收数据小于4字节认为是错误
	if(g_tMods.RxCount < 4)
	{
		goto err_ret;
	}

	// 对接收到的数据取CRC校验, 最后两个字节的CRC不正确则计算结果不为0
	crc1 = CRC16_Modbus(g_tMods.RxBuf, g_tMods.RxCount);
	if(crc1 != 0)
	{
		goto err_ret;
	}

	addr = g_tMods.RxBuf[0];		// 从站地址
	if(addr != SADDR485)
	{
		goto err_ret;
	}

	MODS_AnalyzeApp();					// 解析、回复处理

err_ret:
	g_tMods.RxCount = 0;				// 接收计算清零，方便下次帧同步
}


/* RTU功能码解析处理 */
static void MODS_AnalyzeApp(void)
{
	// 判断功能码
	switch(g_tMods.RxBuf[1])
	{
	case 0x01:
		MODS_01H();											// 解析并应答	
		bsp_PutMsg(MSG_MODS_01H, 0);		// 发送接收到01功能码的消息
		break;

	case 0x02:
		MODS_02H();											// 读取离散输入寄存器值
		bsp_PutMsg(MSG_MODS_02H, 0);
		break;

	case 0x03:
		MODS_03H();											// 读保持寄存器(模拟量输出)
		bsp_PutMsg(MSG_MODS_03H, 0);
		break;

	case 0x04:												// 读输入寄存器(模拟量输入)
		MODS_04H();
		bsp_PutMsg(MSG_MODS_04H, 0);	
		break;

	case 0x05:												// 写单个线圈
		MODS_05H();
		bsp_PutMsg(MSG_MODS_05H, 0);	
		break;
	
	case 0x06:												// 写保持寄存器(写模拟量输出值)
		MODS_06H();
		bsp_PutMsg(MSG_MODS_06H, 0);
		break;

	case 0x10:												// 连续写多个保持寄存器
		MODS_10H();
		bsp_PutMsg(MSG_MODS_10H, 0);
		break;

	default:
		g_tMods.RspCode = RSP_ERR_CMD;		
		MODS_SendAckErr(g_tMods.RspCode);	// 回复错误应答
		break;
	}
}

/* 3.5字符超时回调函数 */
static void MODS_RxTimeOut(void)
{
	g_mods_timeout = 1;
}

/**
 * @brief		接收数据
 * @param		_byte: 从串口接收到的一个字节
 * @retval	None
 * @note		每收到一个字节执行一次
 */
void MODS_ReceiveNew(uint8_t _byte)
{
	/*
		3.5个字符的时间间隔，只是用在RTU模式下面，因为RTU模式没有开始符和结束符，
		两个数据包之间只能靠时间间隔来区分，Modbus定义在不同的波特率下，间隔时间是不一样的，
		所以就是3.5个字符的时间，波特率高，这个时间间隔就小，波特率低，这个时间间隔相应就大

		(1 + 8 + 1) * 3.5 * 1000 / baud 
		
		4800  = 7.297ms
		9600  = 3.646ms
	*/	

	uint32_t timeout;

	g_mods_timeout = 0;

	timeout = 35000000 / SBAUD485;		// 计算超时时间
	// 开启3.5字符超时判断
	bsp_startHardTimer(1, timeout, (void*)MODS_RxTimeOut);

	if(g_tMods.RxCount < S_RX_BUF_SIZE)
	{
		g_tMods.RxBuf[g_tMods.RxCount++] = _byte;
	}
}

